package com.zh.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zh.common.ErrorCode;
import com.zh.constant.ProjectConstant;
import com.zh.domain.dto.project.*;
import com.zh.domain.entity.*;
import com.zh.domain.vo.milestone.MileStoneVo;
import com.zh.domain.vo.project.ProjectVo;
import com.zh.domain.vo.task.TaskCountVo;
import com.zh.domain.vo.task.TaskVo;
import com.zh.domain.vo.user.UserVO;
import com.zh.exception.ThrowUtils;
import com.zh.mapper.ProjectMapper;
import com.zh.mapper.ProjectUserMapper;
import com.zh.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Administrator
 * @description 针对表【projects(项目表)】的数据库操作Service实现
 * @createDate 2025-02-09 16:24:10
 */
@Service
@Slf4j
public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project>
        implements ProjectService {

    @Resource
    private UserService userService;
    @Resource
    private ProjectUserService projectUserService;
    @Resource
    private TeamService teamService;
    @Resource
    private MessageService messageService;
    @Resource
    private ProjectDynamicsService projectDynamicsService;
    @Resource
    private ProjectMapper projectMapper;
    @Resource
    private ProjectUserMapper projectUserMapper;
    @Lazy
    @Resource
    private MilestoneService milestoneService;
    @Lazy
    @Resource
    private TaskService taskService;


    // region
    @Override
    @Transactional
    public Integer addProject(AddProjectRequest projectRequest) {
        // 1. 参数校验
        int loginId = StpUtil.getLoginIdAsInt();
        Integer teamId = projectRequest.getTeamId();
        String title = projectRequest.getTitle();
        String description = projectRequest.getDescription();
        Integer ownerId = projectRequest.getOwnerId();
        Integer status = projectRequest.getStatus();
        LocalDateTime startTime = projectRequest.getStartTime();
        LocalDateTime endTime = projectRequest.getEndTime();
        Integer canDelay = projectRequest.getCanDelay();
        List<Integer> memberIds = projectRequest.getMemberIds();
        ThrowUtils.throwIf(teamId == null, ErrorCode.PARAMS_ERROR, "团队id不能为空");
        ThrowUtils.throwIf(title == null || title.length() > 20, ErrorCode.PARAMS_ERROR, "项目名称不超过20字");
        ThrowUtils.throwIf(startTime == null, ErrorCode.PARAMS_ERROR, "项目开始时间不能为空");
        ThrowUtils.throwIf(CollectionUtil.isEmpty(memberIds), ErrorCode.PARAMS_ERROR, "项目成员不能为空");
        // 2. 赋初值
        if (null == endTime) {
            projectRequest.setEndTime(LocalDateTime.of(2099, 12, 31, 23, 59, 59));
        }
        if (null == canDelay) {
            projectRequest.setCanDelay(1);
        }
        if (null == status) {
            projectRequest.setStatus(ProjectConstant.PROJECT_STATUS_PLANNING);
        }

        // 3. 添加项目
        Project project = new Project();
        BeanUtil.copyProperties(projectRequest, project);
        project.setCreateBy(loginId);
        project.setUpdateBy(loginId);
        project.setCreateAt(LocalDateTime.now());
        project.setUpdateAt(LocalDateTime.now());
        //4. 生成并设置项目编号
        LambdaQueryWrapper<Project> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Project::getTeamId, teamId)
                .orderByDesc(Project::getId)
                .last("limit 1");
        Project lastOne = this.getOne(queryWrapper);
        if (null == lastOne) {
            project.setCode(teamId + "" + 1);
        } else {
            int nowId = lastOne.getId() + 1;
            project.setCode(teamId + "" + nowId);
        }
        project.setDeleted(0);
        boolean saved = this.save(project);
        ThrowUtils.throwIf(!saved, ErrorCode.OPERATION_ERROR, "项目添加失败", (e) -> {
            log.error("项目添加失败,数据库插入失败", e);
        });

        //5.插入项目用户表
        List<ProjectUser> projectUserList = memberIds.stream().map(memberId -> {
            ProjectUser projectUser = new ProjectUser();
            projectUser.setUserId(memberId);
            projectUser.setProId(project.getId());
            projectUser.setRole(loginId == ownerId ? 1 : 0);
            return projectUser;
        }).collect(Collectors.toList());
        projectUserService.saveBatch(projectUserList);
        //6.插入项目动态表
        List<UserVO> userVOList = userService.listUserVoByIds(memberIds);
        List<ProjectDynamics> dynamicsList = userVOList.stream().map(userVO -> {
            ProjectDynamics dynamics = new ProjectDynamics();
            dynamics.setProId(project.getId());
            dynamics.setContent(userVO.getName() + "加入项目-" + title + "-" + project.getCode());
            dynamics.setCreateAt(LocalDateTime.now());
            dynamics.setCreateBy(loginId);
            dynamics.setUpdateAt(LocalDateTime.now());
            dynamics.setUpdateBy(loginId);
            dynamics.setStatus(1);
            dynamics.setDeleted(0);
            return dynamics;
        }).collect(Collectors.toList());

        UserVO userVO = userService.getUserVoById(loginId);
        String name = userVO.getName();
        ProjectDynamics dynamics = new ProjectDynamics();
        dynamics.setProId(project.getId());
        dynamics.setContent(name + "创建了项目" + title + "-" + project.getCode() + '.');
        dynamics.setCreateAt(LocalDateTime.now());
        dynamics.setCreateBy(loginId);
        dynamics.setUpdateAt(LocalDateTime.now());
        dynamics.setUpdateBy(loginId);
        dynamics.setStatus(1);
        dynamics.setDeleted(0);
        dynamicsList.add(0, dynamics);
        projectDynamicsService.saveBatch(dynamicsList);
        return project.getId();
    }

    @Override
    @Transactional
    public Boolean updateProject(UpdateProjectRequest updateRequest) {
        ProjectService proxy = (ProjectService) AopContext.currentProxy();
        //1.参数校验
        int loginId = StpUtil.getLoginIdAsInt();
        Integer id = updateRequest.getId();
        Integer ownerId = updateRequest.getOwnerId();
        String description = updateRequest.getDescription();
        LocalDateTime startTime = updateRequest.getStartTime();
        LocalDateTime endTime = updateRequest.getEndTime();
        String remark = updateRequest.getRemark();
        Integer status = updateRequest.getStatus();
        ThrowUtils.throwIf(null != status && !ProjectConstant.isValidStatus(status), ErrorCode.PARAMS_ERROR, "状态值非法");
        ThrowUtils.throwIf(startTime != null && endTime != null && startTime.isAfter(endTime), ErrorCode.PARAMS_ERROR, "开始时间不能大于结束时间");
        //2.权限校验
        ThrowUtils.throwIf(id == null, ErrorCode.PARAMS_ERROR, "项目id不能为空");
        Project oldProject = proxy.getById(id);
        ThrowUtils.throwIf(oldProject == null, ErrorCode.PARAMS_ERROR, "项目不存在");
        int oldOwnerId = oldProject.getOwnerId();

        //登录id!=原项目负责人id
        ThrowUtils.throwIf(loginId != oldOwnerId, ErrorCode.FORBIDDEN_ERROR, "无权限");
        // 如果更新负责人,将其role设置为1,原来的设为0
        if (ownerId != null && ownerId != oldOwnerId) {
            LambdaUpdateWrapper<ProjectUser> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(ProjectUser::getProId, id)
                    .eq(ProjectUser::getUserId, ownerId)
                    .set(ProjectUser::getRole, 1);
            projectUserService.update(updateWrapper);
            LambdaUpdateWrapper<ProjectUser> updateWrapper1 = new LambdaUpdateWrapper<>();
            updateWrapper1.eq(ProjectUser::getProId, id)
                    .eq(ProjectUser::getUserId, oldOwnerId)
                    .set(ProjectUser::getRole, 0);
            projectUserService.update(updateWrapper1);

            //插入项目动态 发送通知
            saveProjectDynamicUpdated(oldProject, oldOwnerId, ownerId);
        }
        //3.更新项目
        Project project = new Project();
        //忽略null
        BeanUtil.copyProperties(updateRequest, project, CopyOptions.create().ignoreNullValue());
        project.setId(id);
        project.setUpdateAt(LocalDateTime.now());
        project.setUpdateBy(loginId);
        boolean success = proxy.updateById(project);

        //4.更新项目动态表 这里需要更多的消息类型
        if (success) {
            saveProjectDynamicUpdated(oldProject, project);
        }

        return success;
    }


    @Override
    public Page<ProjectVo> pageProject(PageProjectRequest pageRequest) {
        // 1. 参数校验
        pageValidatePageProjectRequest(pageRequest);

        // 2. 权限校验
        int loginId = StpUtil.getLoginIdAsInt();
        pageValidateTeamPermission(loginId, pageRequest.getTeamId());

        // 3. 分页查询项目
        Page<Project> projectPage = pageQueryProjects(pageRequest);

        // 4. 提取项目信息
        List<Project> projectList = projectPage.getRecords();
        if (CollectionUtil.isEmpty(projectList)) {
            return new Page<>(pageRequest.getCurrent(), pageRequest.getPageSize());
        }

        // 5. 查询项目成员和创建者信息
        Map<Integer, List<ProjectUser>> projectUserMap = pageQueryProjectUsers(projectList);
        Map<Integer, UserVO> userVOMap = pageQueryUserVOs(projectList, projectUserMap);

        // 6. 封装项目成员信息
        List<ProjectVo> projectVoList = pageAssembleProjectVoList(projectList, projectUserMap, userVOMap, loginId);

        // 7. 设置分页信息
        Page<ProjectVo> projectVoPage = new Page<>(pageRequest.getCurrent(), pageRequest.getPageSize());
        BeanUtil.copyProperties(projectPage, projectVoPage);

        //8. 若非团队管理员,过滤出我参与的项目
        Integer teamId = pageRequest.getTeamId();
        User user = userService.getById(loginId);
        Team team = teamService.getById(teamId);
        boolean isTeamAdmin = Objects.equals(team.getOwnerId(), user.getId());
        if (!isTeamAdmin) {
            List<Integer> projectIds = projectVoList.stream().map(ProjectVo::getId).collect(Collectors.toList());
            LambdaQueryWrapper<ProjectUser> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ProjectUser::getUserId, loginId)
                    .in(ProjectUser::getProId, projectIds);
            List<ProjectUser> projectUsers = projectUserService.list(queryWrapper);
            projectVoList = projectVoList.stream()
                    .filter(projectVo -> projectUsers.stream().anyMatch(projectUser -> projectUser.getProId().equals(projectVo.getId())))
                    .collect(Collectors.toList());
        }
        //9.查询里程碑和任务
        projectVoList.forEach(projectVo -> {
            Integer proId = projectVo.getId();
            List<TaskVo> taskVoList = taskService.listByProIdDirectly(proId);
            List<MileStoneVo> mileStoneVoList = milestoneService.listByProId(proId);
            projectVo.setTaskVoList(taskVoList);
            projectVo.setMileStoneVoList(mileStoneVoList);
        });
        projectVoPage.setRecords(projectVoList);
        return projectVoPage;
    }

    @Override
    public List<ProjectVo> listMyTeamProject(Integer teamId, int loginId) {
        return projectMapper.listMyTeamProject(teamId, loginId);
    }

    @Override
    @Transactional
    public boolean removeUserByProIdAndUserIdList(RemoveMembersRequest removeMembersRequest) {
        ProjectService proxy = (ProjectService) AopContext.currentProxy();
        Integer proId = removeMembersRequest.getProId();
        List<Integer> userIdList = removeMembersRequest.getUserIdList();
        int loginId = StpUtil.getLoginIdAsInt();

        // 参数校验
        validateProjectAndPermissions(proId, userIdList);

        // 权限校验
        checkAdminPermission(proId, loginId);

        // 删除项目-用户表
        boolean result = projectUserMapper.removeUserByProIdAndUserIdList(proId, userIdList) > 0;

        // 插入项目动态表和发送消息通知
        Project project = proxy.getById(proId);
        addOrRemoveProjectDynamicsAndSendMessage(false, proId, userIdList, loginId, project.getTitle());

        return result;
    }


    @Override
    @Transactional
    public boolean addMembers(AddMembersRequest addMembersRequest) {
        ProjectService proxy = (ProjectService) AopContext.currentProxy();
        Integer proId = addMembersRequest.getProId();
        List<Integer> userIdList = addMembersRequest.getUserIdList();
        int loginId = StpUtil.getLoginIdAsInt();

        // 参数校验
        validateProjectAndPermissions(proId, userIdList);

        // 权限校验
        checkAdminPermission(proId, loginId);

        // 插入项目-用户表
        List<ProjectUser> projectUserList = userIdList.stream()
                .map(userId -> {
                    ProjectUser projectUser = new ProjectUser();
                    projectUser.setProId(proId);
                    projectUser.setUserId(userId);
                    projectUser.setRole(0);
                    return projectUser;
                }).collect(Collectors.toList());
        boolean saved = projectUserService.saveBatch(projectUserList);

        // 插入项目动态表和发送消息通知
        Project project = proxy.getById(proId);
        addOrRemoveProjectDynamicsAndSendMessage(true, proId, userIdList, loginId, project.getTitle());

        return saved;
    }


    public ProjectVo getProject(Integer id) {
        int loginId = StpUtil.getLoginIdAsInt();
        ThrowUtils.throwIf(null == id, ErrorCode.PARAMS_ERROR);
        Project project = projectMapper.selectById(id);
        ProjectVo projectVo = BeanUtil.copyProperties(project, ProjectVo.class);
        // 查询项目成员和创建者信息
        LambdaQueryWrapper<ProjectUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProjectUser::getProId, id);
        List<ProjectUser> projectUserList = projectUserService.list(queryWrapper);
        List<Integer> userIdList = new ArrayList<>();
        List<Integer> projectUserIdList = projectUserList.stream().map(ProjectUser::getUserId).collect(Collectors.toList());
        userIdList.add(project.getCreateBy());
        userIdList.add(project.getOwnerId());
        userIdList.addAll(projectUserIdList);
        List<UserVO> userVOList = userService.listUserVoByIds(userIdList);
        Map<Integer, UserVO> userVOMap = userVOList.stream().collect(Collectors.toMap(UserVO::getId, userVO -> userVO));
        projectVo.setMembers(userVOList.stream().filter(userVO -> projectUserIdList.contains(userVO.getId())).collect(Collectors.toList()));
        projectVo.setCreator(userVOMap.get(project.getCreateBy()));
        projectVo.setOwner(userVOMap.get(project.getOwnerId()));
        ProjectUser projectUser = projectUserList.stream()
                .filter(projectUser1 ->
                        (projectUser1.getUserId()).equals(loginId))
                .collect(Collectors.toList()).get(0);
        projectVo.setTag(projectUser.getTag());
        projectVo.setRole(projectUser.getRole());
        //查询里程碑和任务
        List<TaskVo> taskVoList = taskService.listByProIdDirectly(id);
        List<MileStoneVo> mileStoneVoList = milestoneService.listByProId(id);
        projectVo.setTaskVoList(taskVoList);
        projectVo.setMileStoneVoList(mileStoneVoList);
        return projectVo;
    }

    @Override
    public void updateProcessById(Integer proId) {
        List<TaskVo> taskVos = taskService.listByProId(proId);
        if (CollectionUtil.isEmpty(taskVos)) {
            return;
        }
        long completeCount = taskVos.stream().filter(taskVo -> taskVo.getStatus() == 4).count();
        BigDecimal progress = new BigDecimal(completeCount).divide(new BigDecimal(taskVos.size()), 2, RoundingMode.HALF_UP);
        Project project = new Project();
        if (progress.compareTo(BigDecimal.valueOf(1)) == 0) {
            project.setStatus(4);
        }
        project.setId(proId);
        project.setProgress(progress);
        project.setUpdateAt(LocalDateTime.now());
        projectMapper.updateById(project);
    }

    @Override
    public TaskCountVo getTaskCount(Integer proId) {
        List<TaskVo> taskVoList = taskService.listByProId(proId);
        TaskCountVo taskCountVo = new TaskCountVo();
        taskCountVo.setProId(proId);

        int totalTask = 0;
        int doneTask = 0;
        int doingTask = 0;
        int undoTask = 0;
        int unStartTask = 0;
        int overdueTask = 0;
        int todayTask = 0;
        double process = 0.0;
        double overDueRate = 0.0;
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        for (TaskVo taskVo : taskVoList) {
            totalTask++;
            int status = taskVo.getStatus();
            switch (status) {
                case 0: // 规划中
                    unStartTask++;
                    break;
                case 1: // 进行中
                    doingTask++;
                    break;
                case 3: // 已逾期
                    overdueTask++;
                    break;
                case 4: // 已完成
                    doneTask++;
                    break;
//                case 5: // 已废弃
//                    undoTask++;
//                    break;
                default:
                    undoTask++;
                    break;
            }

            // 判断今日到期任务
            if (taskVo.getEndTime() != null && taskVo.getEndTime().format(formatter).equals(now.format(formatter))) {
                todayTask++;
            }
        }
        // 计算完成进度和逾期率
        if (totalTask > 0) {
            process = (double) doneTask / totalTask;
            overDueRate = (double) overdueTask / totalTask;
        }
        taskCountVo.setTotalTask(totalTask);
        taskCountVo.setDoneTask(doneTask);
        taskCountVo.setDoingTask(doingTask);
        taskCountVo.setUndoTask(undoTask);
        taskCountVo.setUnStartTask(unStartTask);
        taskCountVo.setOverdueTask(overdueTask);
        taskCountVo.setTodayTask(todayTask);
        taskCountVo.setProcess(process);
        taskCountVo.setOverDueRate(overDueRate);
        return taskCountVo;
    }

    private void pageValidatePageProjectRequest(PageProjectRequest pageRequest) {
        BigDecimal leftProgress = pageRequest.getLeftProgress();
        BigDecimal rightProgress = pageRequest.getRightProgress();
        LocalDateTime startTime = pageRequest.getStartTime();
        LocalDateTime endTime = pageRequest.getEndTime();
        Integer status = pageRequest.getStatus();
        Integer ownerId = pageRequest.getOwnerId();
        Integer teamId = pageRequest.getTeamId();
        String title = pageRequest.getTitle();
        Integer canDelay = pageRequest.getCanDelay();

        ThrowUtils.throwIf(leftProgress != null && (leftProgress.compareTo(BigDecimal.ZERO) < 0 || leftProgress.compareTo(BigDecimal.valueOf(100)) > 0), ErrorCode.PARAMS_ERROR, "进度值非法");
        ThrowUtils.throwIf(rightProgress != null && (rightProgress.compareTo(BigDecimal.ZERO) < 0 || rightProgress.compareTo(BigDecimal.valueOf(100)) > 0), ErrorCode.PARAMS_ERROR, "进度值非法");
        ThrowUtils.throwIf(startTime != null && endTime != null && startTime.isAfter(endTime), ErrorCode.PARAMS_ERROR, "开始时间不能大于结束时间");
        ThrowUtils.throwIf(status != null && !ProjectConstant.isValidStatus(status), ErrorCode.PARAMS_ERROR, "状态值非法");
        pageRequest.standardizeSize();
    }

    private void pageValidateTeamPermission(int loginId, Integer teamId) {
        Boolean inTeam = teamService.isInTeam(teamId, loginId);
        ThrowUtils.throwIf(!inTeam, ErrorCode.FORBIDDEN_ERROR, "无权限");
    }

    private Page<Project> pageQueryProjects(PageProjectRequest pageRequest) {
        Integer current = pageRequest.getCurrent();
        Integer pageSize = pageRequest.getPageSize();
        Page<Project> page = new Page<>(current, pageSize);
        LambdaQueryWrapper<Project> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(pageRequest.getId() != null, Project::getId, pageRequest.getId())
                .gt(pageRequest.getLeftProgress() != null, Project::getProgress, pageRequest.getLeftProgress())
                .lt(pageRequest.getRightProgress() != null, Project::getProgress, pageRequest.getRightProgress())
                .ge(pageRequest.getStartTime() != null, Project::getStartTime, pageRequest.getStartTime())
                .le(pageRequest.getEndTime() != null, Project::getEndTime, pageRequest.getEndTime())
                .eq(pageRequest.getStatus() != null, Project::getStatus, pageRequest.getStatus())
                .eq(pageRequest.getOwnerId() != null, Project::getOwnerId, pageRequest.getOwnerId())
                .eq(pageRequest.getTeamId() != null, Project::getTeamId, pageRequest.getTeamId())
                .like(StrUtil.isNotEmpty(pageRequest.getTitle()), Project::getTitle, pageRequest.getTitle())
                .eq(pageRequest.getCanDelay() != null, Project::getCanDelay, pageRequest.getCanDelay())
                .orderByDesc(Project::getUpdateAt);

        return this.page(page, queryWrapper);
    }

    private Map<Integer, List<ProjectUser>> pageQueryProjectUsers(List<Project> projectList) {
        List<Integer> projectIdList = projectList.stream().map(Project::getId).collect(Collectors.toList());
        LambdaQueryWrapper<ProjectUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(ProjectUser::getProId, projectIdList);
        List<ProjectUser> projectUserList = projectUserService.list(queryWrapper);
        if (CollectionUtil.isEmpty(projectUserList)) {
            return Collections.emptyMap();
        }
        return projectUserList.stream().collect(Collectors.groupingBy(ProjectUser::getProId));
    }

    private Map<Integer, UserVO> pageQueryUserVOs(List<Project> projectList, Map<Integer, List<ProjectUser>> projectUserMap) {
        List<Integer> userIdList = projectUserMap.values().stream()
                .flatMap(List::stream)
                .map(ProjectUser::getUserId)
                .collect(Collectors.toList());

        List<Integer> creatorIdList = projectList.stream()
                .map(Project::getCreateBy)
                .collect(Collectors.toList());

        userIdList.addAll(creatorIdList);

        List<UserVO> userVOList = userService.listUserVoByIds(userIdList);
        return userVOList.stream().collect(Collectors.toMap(UserVO::getId, userVO -> userVO));
    }

    private List<ProjectVo> pageAssembleProjectVoList(List<Project> projectList, Map<Integer, List<ProjectUser>> projectUserMap, Map<Integer, UserVO> userVOMap, int loginId) {
        return projectList.stream().map(project -> {
            ProjectVo projectVo = new ProjectVo();
            BeanUtil.copyProperties(project, projectVo);

            // 获取项目成员信息
            List<ProjectUser> projectUsers = projectUserMap.getOrDefault(project.getId(), Collections.emptyList());

            // 找到本人信息
            ProjectUser me = projectUsers.stream()
                    .filter(projectUser -> projectUser.getUserId().equals(loginId))
                    .findFirst()
                    .orElse(null);
            if (me != null) {
                projectVo.setTag(me.getTag());
                projectVo.setRole(me.getRole());
            }

            // 找到负责人信息
            UserVO owner = userVOMap.get(project.getOwnerId());
            if (owner != null) {
                projectVo.setOwner(owner);
            }

            // 找到创建人信息
            UserVO creator = userVOMap.get(project.getCreateBy());
            if (creator != null) {
                projectVo.setCreator(creator);
            }

            // 找到所有成员信息
            List<UserVO> members = projectUsers.stream()
                    .map(projectUser -> userVOMap.get(projectUser.getUserId()))
                    .filter(Objects::nonNull)
                    .collect(Collectors.toList());
            projectVo.setMembers(members);

            return projectVo;
        }).collect(Collectors.toList());
    }

    // endregion
    private void validateProjectAndPermissions(Integer proId, List<Integer> userIdList) {
        ThrowUtils.throwIf(proId == null, ErrorCode.PARAMS_ERROR);
        ThrowUtils.throwIf(CollectionUtil.isEmpty(userIdList), ErrorCode.PARAMS_ERROR);
        Project project = this.getById(proId);
        ThrowUtils.throwIf(null == project, ErrorCode.PARAMS_ERROR, "项目不存在");
    }

    private void checkAdminPermission(Integer proId, int loginId) {
        LambdaQueryWrapper<ProjectUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProjectUser::getProId, proId)
                .eq(ProjectUser::getUserId, loginId)
                .eq(ProjectUser::getRole, 1);
        ProjectUser projectUser = projectUserService.getOne(queryWrapper);
        ThrowUtils.throwIf(null == projectUser || projectUser.getRole() != 1, ErrorCode.NO_AUTH_ERROR, "只有项目管理员才能添加成员");
    }

    private void addOrRemoveProjectDynamicsAndSendMessage(boolean isAdd, Integer proId, List<Integer> userIdList, int loginId, String projectName) {
        UserVO creator = userService.getUserVoById(loginId);
        List<UserVO> userVOList = userService.listUserVoByIds(userIdList);

        // 插入项目动态表
        List<ProjectDynamics> dynamicsList = userVOList.stream()
                .map(userVO ->
                {
                    ProjectDynamics dynamics = new ProjectDynamics();
                    String content = "";
                    if (isAdd) {
                        content = String.format("%s 邀请 %s 加入项目", creator.getName(), userVO.getName());
                    } else {
                        content = String.format("%s 已离开项目 %s", userVO.getName(), projectName);
                    }
                    dynamics.setProId(proId);
                    dynamics.setContent(content);
                    dynamics.setCreateAt(LocalDateTime.now());
                    dynamics.setCreateBy(loginId);
                    dynamics.setUpdateAt(LocalDateTime.now());
                    dynamics.setUpdateBy(loginId);
                    dynamics.setStatus(1);
                    dynamics.setDeleted(0);
                    return dynamics;
                }).collect(Collectors.toList());
        projectDynamicsService.saveBatch(dynamicsList);
        // 发送消息通知
        Message message = new Message();
        message.setSendId(loginId);
        String content;
        if (isAdd) {
            content = String.format("%s 邀请你加入项目 %s", creator.getName(), projectName);
        } else {
            content = String.format("你已离开项目 %s ", projectName);
        }
        message.setContent(content);
        message.setCreateAt(LocalDateTime.now());
        message.setCreateBy(loginId);
        message.setUpdateAt(LocalDateTime.now());
        message.setUpdateBy(loginId);
        message.setNoticeType(0);
        message.setType(1);
        message.setParams(Map.of(
                "proId", proId.toString(),
                "payloadType", "project",
                "title", projectName
        ));
        message.setStatus(1);
        messageService.sendMessage(message, userIdList);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void saveProjectDynamicUpdated(Project oldProject, Project newProject) {
        //1.取出项目参数
        int loginId = StpUtil.getLoginIdAsInt();
        Integer oldOwnerId = oldProject.getOwnerId();
        String oldTitle = oldProject.getTitle();
        String title = newProject.getTitle();
        Integer ownerId = newProject.getOwnerId();
        Integer proId = newProject.getId();
        String description = newProject.getDescription();
        String remark = newProject.getRemark();
        LocalDateTime startTime = newProject.getStartTime();
        LocalDateTime endTime = newProject.getEndTime();
        Integer status = newProject.getStatus();
        UserVO userVO = userService.getUserVoById(loginId);
        String name = userVO.getName();
        ProjectDynamics templateDynamics = new ProjectDynamics();
        templateDynamics.setProId(proId);
        templateDynamics.setCreateAt(LocalDateTime.now());
        templateDynamics.setCreateBy(loginId);
        templateDynamics.setUpdateAt(LocalDateTime.now());
        templateDynamics.setUpdateBy(loginId);
        templateDynamics.setStatus(1);
        templateDynamics.setDeleted(0);
        StringBuilder contentBuilder = new StringBuilder();
        List<ProjectDynamics> dynamicsList = new ArrayList<>();
        if (title != null) {
            contentBuilder.append(userVO.getName())
                    .append("将项目名从 ")
                    .append(oldTitle)
                    .append(" 修改为 ")
                    .append(title)
                    .append(".");
            ProjectDynamics dynamics = BeanUtil.copyProperties(templateDynamics, ProjectDynamics.class);
            dynamics.setContent(contentBuilder.toString());
            dynamicsList.add(dynamics);
            contentBuilder.setLength(0);
        }
        if (ownerId != null) {
            User oldOwner = userService.getById(oldOwnerId);
            contentBuilder.append(userVO.getName())
                    .append("将项目负责人由")
                    .append(oldOwner.getName())
                    .append("修改为")
                    .append(userService.getUserVoById(ownerId).getName())
                    .append(".");
            ProjectDynamics dynamics = BeanUtil.copyProperties(templateDynamics, ProjectDynamics.class);
            dynamics.setContent(contentBuilder.toString());
            dynamicsList.add(dynamics);
            contentBuilder.setLength(0);
        }
        if (description != null) {
            contentBuilder.append(userVO.getName())
                    .append("修改了项目简介.");
            ProjectDynamics dynamics = BeanUtil.copyProperties(templateDynamics, ProjectDynamics.class);
            dynamics.setContent(contentBuilder.toString());
            dynamicsList.add(dynamics);
            contentBuilder.setLength(0);
        }
        if (remark != null) {
            contentBuilder.append(userVO.getName())
                    .append("修改了项目备注.");
            ProjectDynamics dynamics = BeanUtil.copyProperties(templateDynamics, ProjectDynamics.class);
            dynamics.setContent(contentBuilder.toString());
            dynamicsList.add(dynamics);
            contentBuilder.setLength(0);
        }
        if (startTime != null) {
            contentBuilder.append(userVO.getName())
                    .append("将项目起始时间从 ")
                    .append(oldProject.getStartTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
                    .append(" 修改为 ")
                    .append(startTime)
                    .append(".");
            ProjectDynamics dynamics = BeanUtil.copyProperties(templateDynamics, ProjectDynamics.class);
            dynamics.setContent(contentBuilder.toString());
            dynamicsList.add(dynamics);
            contentBuilder.setLength(0);
        }
        if (endTime != null) {
            contentBuilder.append(userVO.getName())
                    .append("将项目结束时间从 ")
                    .append(oldProject.getEndTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
                    .append(" 修改为 ")
                    .append(endTime)
                    .append(".");
            ProjectDynamics dynamics = BeanUtil.copyProperties(templateDynamics, ProjectDynamics.class);
            dynamics.setContent(contentBuilder.toString());
            dynamicsList.add(dynamics);
            contentBuilder.setLength(0);
            // 修改的截至时间若小于当前时间,则修改状态为已逾期 若大于当前时间且为已逾期状态,则修改状态为进行中
            ProjectService proxy = (ProjectService) AopContext.currentProxy();
            if (endTime.isBefore(LocalDateTime.now())) {
                Project updateProject = new Project();
                updateProject.setId(proId);
                updateProject.setUpdateAt(LocalDateTime.now());
                updateProject.setUpdateBy(loginId);
                updateProject.setStatus(3);
                proxy.updateById(updateProject);
            } else {
                if (oldProject.getStatus() == 3) {
                    Project updateProject = new Project();
                    updateProject.setId(proId);
                    updateProject.setUpdateAt(LocalDateTime.now());
                    updateProject.setUpdateBy(loginId);
                    updateProject.setStatus(1);
                    proxy.updateById(updateProject);
                }
            }
        }
        if (status != null) {
            contentBuilder.append(userVO.getName())
                    .append("将项目状态从 ")
                    .append(ProjectConstant.getStatusName(oldProject.getStatus()))
                    .append(" 修改为 ")
                    .append(ProjectConstant.getStatusName(status))
                    .append(".");
            ProjectDynamics dynamics = BeanUtil.copyProperties(templateDynamics, ProjectDynamics.class);
            dynamics.setContent(contentBuilder.toString());
            dynamicsList.add(dynamics);
            contentBuilder.setLength(0);
        }
        projectDynamicsService.saveBatch(dynamicsList);
    }

    @Transactional
    public void saveProjectDynamicUpdated(Project oldProject, int oldOwnerId, Integer ownerId) {
        ProjectDynamics dynamics = new ProjectDynamics();
        User oldOwner = userService.getById(oldOwnerId);
        User newOwner = userService.getById(ownerId);
        UserVO operator = userService.getUserVoById(StpUtil.getLoginIdAsInt());
        dynamics.setProId(oldProject.getId());
        dynamics.setContent(String.format("%s 将项目负责人由 %s 修改为 %s",
                operator.getName(),
                oldOwner.getName(),
                newOwner.getName()));
        dynamics.setCreateAt(LocalDateTime.now());
        dynamics.setCreateBy(StpUtil.getLoginIdAsInt());
        dynamics.setUpdateAt(LocalDateTime.now());
        dynamics.setUpdateBy(StpUtil.getLoginIdAsInt());
        dynamics.setStatus(1);
        dynamics.setDeleted(0);
        projectDynamicsService.save(dynamics);
        // 发送通知
        Message message = new Message();
        message.setContent(String.format("%s 将你设置为项目 %s 负责人",
                operator.getName(),
                oldProject.getTitle()));
        message.setCreateAt(LocalDateTime.now());
        message.setCreateBy(StpUtil.getLoginIdAsInt());
        message.setUpdateAt(LocalDateTime.now());
        message.setUpdateBy(StpUtil.getLoginIdAsInt());
        message.setNoticeType(0);
        message.setType(1);
        message.setParams(Map.of(
                "proId", oldProject.getId().toString(),
                "payloadType", "project",
                "title", oldProject.getTitle()
        ));
        message.setStatus(1);
        message.setDeleted(0);
        messageService.sendMessage(message, List.of(ownerId));
    }
}




